Introduction to Lambda Calculus

Overview

The Lambda Caclulus is the standard model used for studying and implementing functional programming languages. It is a good model because it is small and simple but still Turing complete and easy to extend. Below we sketch a definition of the language at a high level and give evidence for its Turing completeness. In a follow up, we will pin down some details around substitution, the key mechanism for evaluating lambda calculus programs, and detail an implementation of the lambda calculus in Lean.

Syntax

Lambda calculus programs are composed of (1) variables, (2) applications (i.e., function calls), and (3) abstractions (i.e., function definitions). We define the syntax of lambda calculus with the following BNF grammar:

  e ::= x             // variable
     |  e e           // function application
     |  λ x . e       // function definition

Let's look at some syntactic examples:

IMAGE

Notice how these two programs only differ in the name that the variable happens to have. Later we will argue that these programs are really equivalent since they only differ in how variables are named.

IMAGE

IMAGE

We use some conventions when writing out lambda calculus terms ("terms" just means programs), to avoid needing a bunch of parentheses:

IMAGE

IMAGE

IMAGE

As a final detail, we will also define a subset of lambda terms called "values" which we think of as programs that are "done executing" (this will be useful in the semantics below and for defining notions like "getting stuck"):

IMAGE

Semantics

OK, now we know what lambda calculus programs are, but not what they mean. Here we'll give a "call-by-value", left-to-right, small step operational semantics:

IMAGE

Repeated with some commentary:

IMAGE

IMAGE

IMAGE

Notice how we've designed the rules so there is at most one point where you can make progress on evaluating a term. Also notice how the only thing we can evaluate are applications: the left hand side of every arrow is an APP!

Let's see some examples:

IMAGE

IMAGE

IMAGE

There are even some terms which we can keep on evaluating forever:

IMAGE

Since the step relation "-->" only shows how a term can take a single step, we'll often want to consider its reflexive, transitive closure "-->*":

IMAGE

To aid exposition, we'll be a little be loose when we write derivations by hand. A single "-->" may actually mean "-->*", and
we may fudge the rules a bit on evaluation order. When we treat the lambda calculus formally in Lean, all these issues will be made completely precise.

Church Encodings

At the top, we claimed that lambda calculus is Turing complete, but so far we've only seen stuff about "grind on the left, grind on the right, substitute"... so when do we get to the actual programming language part? Turns out, we're already done, but it can be hard to see. To illustrate how the lambda calculus as it stands above is already Turing complete, we'll show who to encode several useful programming constructs building from booleans up.

First though, a note on what it means for a language to "support" a feature. Here we'll consider features as abstract data types. Essentially this means that we will describe how values of a particular sort can be created ("introduced") and used ("eliminated").

Booleans

An ADT for booleans in the lambda calculus:

IMAGE

and the same with some commentary:

IMAGE

A couple sanity checks:

IMAGE

IMAGE

This version of booleans is just find, but note that we have to be a little careful using cond since while sometimes it works like in normal programming (for arbitrary values v1 v2):

IMAGE

IMAGE

Notice that things do NOT match "normal" programming if one of the arguments to cond is non-terminating:

IMAGE

We can address this by using "thunks", which will need to do below when we consider recursion.

Pairs

Pairs are pretty straightforward; we just need (1) a way to take two things and "put them in a pair", (2) given a pair, a way to get the first thing out, and (3) given a pair, a way to get the second things out. One way to do this in lambda calculus is:

IMAGE

Some hand-wavy examples with arbitrary values v1 v2 v3:

IMAGE

One interesting coincidence: fst is the same as true and snd is the same as false. This is not a problem for us,
any more than it's a problem for the bit pattern 0b00000000000000000000000000000000 to indicate both integer and floating point 0 in 32-bit x86 assembly. Remember: the syntax only has the meaning we give it! Here we're providing the operations for ADTs so that they provide mechanisms similar to what we're used to in "normal" programming languages.

Lists

With booleans and pairs, we have enough to implement a list ADT. We'll use nested pairs for lists, with the additional detail that we "tag" each cell to indicate whether it is a "cons" or "nil" cell. These tags are essential since otherwise we would not be able to implement functions like is_empty.

IMAGE

To visualize some simple, hand wavy examples for values v1 v2:

IMAGE

Notice how all lists are pairs where the first element is a boolean indicating whether the list is empty. Non-empty lists are a pair where the first element is true and the second element is another pair P such that the first element of P is the "first element of the list" and the second element of P is the tail of the list. Empty lists are also a pair, but the first element is false and it does not matter what the second element is, though here we have used false as a convenient dummy value.

Given this list representation, we can encode some functions over list as well:

IMAGE

Note that tail nil does some weird stuff, but that's OK: the user should never call tail on an empty list, it breaks the contract. Taking the tail of an empty list is like dereferencing a null pointer in C/C++/Java.

Natrual Numbers

We encode the natural number n as a function which takes two arguments and applies the first n times starting with the second:

IMAGE

Note that this is very similar to the way that we defined natural numbers in Lean:

IMAGE

Some functions on numbers:

IMAGE

Sanity check examples starts to get pretty tedious once we have numbers...

IMAGE

etc.

So far we've built up booleans, pairs, lists, and natrual numbers. These features can be composed to build all sorts of other datastructures. For example we can encode strings as lists of numbers where each character is represented by its ASCII enconding or represent integers by pairs of a sign bit (boolean) and a natural number (would need to be careful about "signed zero" issues with that choice though!), etc. Hopefully the above is enough to convince you that, with sufficient effort, we can encode pretty much any type we're used in "normal" programming. There is one feature that's not obvious yet though...

Recursion

How do we get recursion in lambda calculus? It seems like a real chicken and egg problem: in order for a function to call itself, it must first be defined, right? Compilers can help us out in normal programming languages by resolving the functions called in a body after the function is defined. What are we to do in lambda calculus though? Do we need to introduce an explicit notion of environment as we did in IMP? It turns out the answer is "no".

Y

The "Y combinator" is one of many fixed-point combinators we can use to get recursion in the lambda calculus. This one works on the principle of passing a function itself as it's first argument. Thus, if we want to write a recursive function foo, we arrange for foo to take another function as its first argument. Then, when we apply Y to foo, it will reduce to foo foo, thus providing foo a reference to itself and enabling recursion.

That all sounds a bit strange, so let's consider an example: factorial. Here is one version of factorial designed to work with Y:

IMAGE

How does Y manage this feat? Let's walk through it. First the definition:

IMAGE

Let's see what Y g is for some arbitrary value g:

IMAGE

OK, now for a very hand wavy example:

IMAGE

There are several things VERY WRONG with the above "squiggly" example: we are not strictly evaluating left-to-right, we are evaluating implicitly under lambdas, and we are not being strict about how cond works with respect to termination. Hopefully, the above handwave helps your intuition though.

If we want to do this example "for real", i.e., in full detail, it looks like:

(((λf. ((λx. (f (λv. ((x x) v)))) (λx. (f (λv. ((x x) v)))))) (λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x)))))) (λs. (λz. (s (s z)))))

(((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) (λs. (λz. (s (s z)))))

(((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v))) (λs. (λz. (s (s z)))))

((λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x)))) (λs. (λz. (s (s z)))))

((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) (λs. (λz. (s (s z)))))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((((λb. (λp. (λq. ((b p) q)))) (((λs. (λz. (s (s z)))) (λx. (λx. (λy. y)))) (λx. (λy. x)))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((((λb. (λp. (λq. ((b p) q)))) ((λz. ((λx. (λx. (λy. y))) ((λx. (λx. (λy. y))) z))) (λx. (λy. x)))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((((λb. (λp. (λq. ((b p) q)))) ((λx. (λx. (λy. y))) ((λx. (λx. (λy. y))) (λx. (λy. x))))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((((λb. (λp. (λq. ((b p) q)))) ((λx. (λx. (λy. y))) (λx. (λy. y)))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((((λb. (λp. (λq. ((b p) q)))) (λx. (λy. y))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

(((λp. (λq. (((λx. (λy. y)) p) q))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((λq. (((λx. (λy. y)) (λx. ((λs. (λz. (s z))) x))) q)) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

(((λx. (λy. y)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

((λy. y) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)))

(λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))

DONE.

(λx. (λz. (x (x z))))

Getting this output requires fixing our definition of fact to be:

IMAGE

Misc

Here's the OCaml code for getting detailed traces of reductions:

type e =
| Var of string
| App of e * e
| Abs of string * e
let rec str = function
| Var x ->
x
| App (e1, e2) ->
Printf.sprintf "(%s %s)"
(str e1)
(str e2)
| Abs (x, e) ->
Printf.sprintf "(λ%s. %s)" x
(str e)
let isval = function
| Var _ -> false
| App _ -> false
| Abs _ -> true
let rec subst e v x =
match e with
| Var y ->
if x = y
then v
else e
| App (e1, e2) ->
App (subst e1 v x, subst e2 v x)
| Abs (y, e') ->
if x = y
then e
else Abs (y, subst e' v x)
let rec step = function
| Var _ ->
failwith "stuck: cannot step var"
| App (Abs (x, e1), e2) ->
if isval e2 then
subst e1 e2 x
else
App (Abs (x, e1), step e2)
| App (e1, e2) ->
App (step e1, e2)
| Abs _ ->
failwith "done: cannot step abstraction"
let rec sstep = function
| Var x ->
Var x
| App (Abs (x, e1), e2) ->
subst e1 e2 x
| App (e1, e2) ->
App (sstep e1, sstep e2)
| Abs (x, e) ->
Abs (x, sstep e)
let rec simp e =
let e' = sstep e in
if e = e'
then e'
else simp e'
let rec trace ?simplify:(simplify = true) e =
Printf.printf "%s\n\n" (str e);
if isval e then begin
print_string "DONE.\n\n";
begin if simplify then
Printf.printf "%s\n\n" (str (simp e))
end
end else
trace ~simplify:simplify (step e)
let lcID =
Abs ("x", Var "x")
let lcTRUE =
Abs ("x", Abs ("y", Var "x"))
let lcFALSE =
Abs ("x", Abs ("y", Var "y"))
let lcCOND =
Abs ("b", Abs ("p", Abs ("q",
App (App (Var "b", Var "p"), Var "q"))))
let lcNOT =
Abs ("a", App (App (Var "a", lcFALSE), lcTRUE))
let lcAND =
Abs ("a", Abs ("b",
App (App (Var "a", Var "b"), lcFALSE)))
let lcOR =
Abs ("a", Abs ("b",
App (App (Var "a", lcTRUE), Var "b")))
let lcOMEGA =
App ( Abs ("x", App (Var "x", Var "x"))
, Abs ("x", App (Var "x", Var "x")))
let lcMKPAIR =
Abs ("x", Abs ("y", Abs ("s",
App (App (Var "s", Var "x"), Var "y"))))
let lcFST =
Abs ("p", App (Var "p", lcTRUE))
let lcSND =
Abs ("p", App (Var "p", lcFALSE))
let lcNIL =
App (App (lcMKPAIR, lcFALSE), lcFALSE)
let lcCONS =
Abs ("h", Abs ("t",
App ( App (lcMKPAIR, lcTRUE)
, App (App (lcMKPAIR, Var "h"), Var "t"))))
let lcISEMPTY =
Abs ("l", App (lcFST, Var "l"))
let lcHEAD =
Abs ("l", App (lcFST, App (lcSND, Var "l")))
let lcTAIL =
Abs ("l", App (lcSND, App (lcSND, Var "l")))
let lcZERO =
Abs ("s", Abs ("z", Var "z"))
let lcSUCC =
Abs ("n", Abs ("s", Abs ("z",
App (Var "s", (App (App (Var "n", Var "s"), Var "z"))))))
(*
\p. mkpair (succ (fst p)) (fst p)
\p. (\n. mkpair (succ n) n) (fst p)
*)
let lcPREDaux =
Abs ("p",
App ( Abs ("n",
App (App (lcMKPAIR, App (lcSUCC, Var "n")), Var "n"))
, App (lcFST, Var "p")))
let lcPRED =
Abs ("n",
App (lcSND, App (App (Var "n", lcPREDaux),
App (App (lcMKPAIR, lcZERO), lcZERO))))
let lcMKNUM n =
let rec loop i =
if i <= 0
then Var "z"
else App (Var "s", loop (i - 1))
in
Abs ("s", Abs ("z", loop n))
let lcONE =
lcMKNUM 1
let lcTWO =
lcMKNUM 2
let lcTHREE =
lcMKNUM 3
let lcISZERO =
Abs ("n",
App (App (Var "n", Abs ("x", lcFALSE)), lcTRUE))
let lcADD =
Abs ("m", Abs ("n",
App (App (Var "m", lcSUCC), Var "n")))
let lcMUL =
Abs ("m", Abs ("n",
App (App (Var "m", App (lcADD, Var "n")), lcZERO)))
let lcPOW =
Abs ("m", Abs ("n",
App (App (Var "n", App (lcMUL, Var "m")), lcONE)))
let lcSUB =
Abs ("m", Abs ("n",
App (App (Var "n", lcPRED), Var "m")))
let lcTHUNK t =
Abs ("x", App (t, Var "x"))
let lcFACT =
Abs ("f", Abs ("n",
App ( App (App (lcCOND, App (lcISZERO, Var "n")), lcTHUNK lcONE)
, lcTHUNK (App (App (lcMUL, Var "n"), App (Var "f", App (lcPRED, Var "n"))))
)))
let lcY =
Abs ("f",
App ( Abs ("x", App (Var "f",
Abs ("v", App (App (Var "x", Var "x"), Var "v"))))
, Abs ("x", App (Var "f",
Abs ("v", App (App (Var "x", Var "x"), Var "v"))))
))
let _ = trace ~simplify:true (
App (App (lcY, lcFACT), lcTWO)
)
(*
App (lcY, lcFACT)
App (App (lcSUB, lcMKNUM 3), lcMKNUM 2)
App (App (lcSUB, lcMKNUM 2), lcMKNUM 3)
App (lcPRED, lcTHREE)
App (lcISZERO, lcONE)
App (lcISZERO, lcZERO)
App (lcTAIL, App (App (lcCONS, lcZERO), lcNIL))
App (lcHEAD, App (App (lcCONS, lcZERO), lcNIL))
App (App (lcCONS, lcZERO), lcNIL)
App (lcSND, App (App (lcMKPAIR, lcTRUE), lcFALSE))
App (App (App (lcCOND, lcTRUE), lcTRUE), lcOMEGA)
lcOMEGA
App (App (lcOR, lcTRUE), lcFALSE)
App (App (lcMUL, lcMKNUM 2), lcMKNUM 3)
App (App (lcPOW, lcMKNUM 2), lcMKNUM 3)
(Abs ("x", Var "x"))
(App ( Abs ("x", Var "x")
, Abs ("x", Var "x")))
*)